﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.IO;

using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

using Daybreak.Core.SceneGraph;
using Daybreak.Core.Rendering;

namespace Daybreak.Core
{
    /// <summary>
    /// Scene environment data
    /// </summary>
    public partial class Scene : IAsset
    {
        #region nested types

        /// <summary>
        /// The UpAxisType class contains descriptive information about coordinate system of the geometric data.
        /// All coordinates are right-handed by definition. This object specifies which axis is considered up.
        /// The default is the Y-axis.
        /// </summary>
        public enum UpAxisType
        {
            X_UP,
            Y_UP,
            Z_UP,
        }

        /// <summary>
        /// The unit class contains descriptive information about unit of measure. 
        /// It has attributes for the name of the unit and the measurement with respect to the meter. 
        /// </summary>
        public struct MeasureUnit
        {
            public readonly static MeasureUnit Meter = new MeasureUnit("meter", 1);
            public readonly static MeasureUnit Inch = new MeasureUnit("inch", 0.0254f);
            public readonly static MeasureUnit Centimeter = new MeasureUnit("centimeter", 0.01f);
            public readonly static MeasureUnit Foot = new MeasureUnit("foot", 0.01f * 30.48f);

            /// <summary>
            /// The measurement with respect to the meter.
            /// </summary>
            public float ToMeter;

            /// <summary>
            /// The name of the unit.
            /// </summary>
            public string Name;

            public MeasureUnit(string name, float meter)
            {
                Name = name;
                ToMeter = meter;
            }

        }

        #endregion

        /// <summary>
        /// Descriptive information about unit of measure
        /// </summary>
        public MeasureUnit Unit;

        public AnimationLib Animations;
        public ControllerLib Controllers;
        public ImageLib Images;
        public MaterialLib Materials;
        public GeometryLib Geometries;
        public VisualScene SceneInstance;
        public UpdateVisitor Updater;

        public string DocumentName;

        public Scene(string docName, string sceneName)
        {
            DocumentName = docName;

            Unit = MeasureUnit.Meter;

            if (!string.IsNullOrEmpty(sceneName))
                SceneInstance = new VisualScene(sceneName, this);
        }

        public IMaterial BindMaterial(IMaterial oldMat, Scene.Material.Binding[] bindings)
        {
            if (bindings == null)
                return oldMat;

            if (Materials == null)
                return oldMat;

            for (int i = 0; i < bindings.Length; i++)
                if (bindings[i].OldMaterialName == oldMat.Name)
                    return Materials.FindByName(bindings[i].NewMaterialName, false);

            return null;
        }

        public Controller.Skin CreateSkinController(string name)
        {
            if (Controllers == null)
                Controllers = new ControllerLib();

            Controller.Skin skin = new Controller.Skin(name);
            Controllers.ControllerList.Add(skin);

            return skin;
        }

        public Geometry CreateGeometry(string name)
        {
            if (Geometries == null)
                Geometries = new GeometryLib();

            return Geometries.AddGeometry(name);
        }

        public Image CreateImage(string name, string file)
        {
            if (Images == null)
                Images = new ImageLib();

            return Images.AddImage(name, file);
        }

        public Material CreateMaterial(string name, Image diffTexture)
        {
            if (Materials == null)
                Materials = new MaterialLib();

            return Materials.AddMaterial(name, diffTexture);
        }

        #region IAsset Members

        public void Accept(Streamer streamer)
        {
            throw new NotImplementedException();
        }

        public void Initialize()
        {
            throw new NotImplementedException();
        }

        public IAsset Clone()
        {
            Scene scene = new Scene(null, null);
            scene.Unit = this.Unit;

            return scene;
        }

        #endregion

    }

    /// <summary>
    /// Provides axis correction methods for custom coordinate spaces
    /// </summary>
    public interface IAxisCorrector
    {
        void CorrectPosition(ref Vector3 pos);
        void CorrectVector(ref Vector3 vec);
        void CorrectMatrix(ref Matrix mat);
        void CorrectTopology(Drawable.Topology topology);

        void MeasureVector(ref Vector3 pos);
        float TargetScale { get; }

    }

}
